home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tp6bugs6.zip / TVBUGS < prev    next >
Internet Message Format  |  1991-12-02  |  33KB

  1. From @ugw.utcs.utoronto.ca:INJS@DCZTU1.BITNET Tue Nov 19 10:55:08 1991
  2. Return-Path: <@ugw.utcs.utoronto.ca:INJS@DCZTU1.BITNET>
  3. Received: from ugw.utcs.utoronto.ca by math.carleton.ca (4.1/SMI-4.0)
  4.     id AA09948; Tue, 19 Nov 91 10:54:44 EST
  5. Received: from IBM.RZ.TU-CLAUSTHAL.DE by ugw.utcs.utoronto.ca with BSMTP id <23337>; Tue, 19 Nov 1991 10:48:09 -0500
  6. Received: from DCZTU1 (INJS) by IBM.RZ.TU-CLAUSTHAL.DE (Mailer R2.08) with
  7.  BSMTP id 2142; Tue, 19 Nov 91 11:18:49 MEZ
  8. Date:     Tue, 19 Nov 1991 05:10:38 -0500
  9. From: Juergen Schlegelmilch <injs%dcztu1.bitnet@utcs.utoronto.ca>
  10. Subject:      Re: TP6.0 bug list
  11. To: Duncan Murdoch <dmurdoch@math.carleton.ca>
  12. In-Reply-To:  Your message of Wed, 30 Oct 1991 08:37:43 -0500
  13. Message-Id: <91Nov19.104809est.23337@ugw.utcs.utoronto.ca>
  14. Status: OR
  15.  
  16. >Thanks, modifications to tvdemos programs would be fine.  If you can, please
  17. >package up the whole program; a "diff" file would be hard to apply since I
  18. >have a different version of the files than you do.  It'll also make it clearer
  19. >which bugs have been addressed in the June 91 release.
  20. Now I'm ready. Since there is one program being very similar to TVEDIT.PAS
  21. I just gave the additions to that file. Including the whole file would be
  22. a waste of space.
  23.  
  24. >> >bugs@borland.com).  Have you already done that?
  25. >> No.
  26. >I'll wait for you demonstration code then, and send it myself.
  27. Meanwhile I got the address of Sydney Markowitz (sydney@borland.com)
  28. and sent him the list. You can send it to bugs@borland.com anyway.
  29. And now the list:
  30.  
  31. Bugs in TurboVision and TurboPascal 6.0
  32.  This file contains a collection of bugs found in Borland's
  33. TurboPascal 6.0 compiler and the TurboVision units. Each
  34. bug is described in the following form:
  35.  
  36.    Bug: procedure/function name (Unit name)
  37.      short description explaining the context and effect
  38.    Example:
  39.      sample Pascal text or name of file, with instructions
  40.      how to see the bug in effect. CAUTION: some bugs will
  41.      cause the system to hang, so be sure to save all your
  42.      important data.
  43.      Some of the sample programs are appended to this text,
  44.      separated by lines like:
  45.          ---------  FILENAME.PAS  -------------------
  46.      One of them, EDIT.PAS, is derived from TVEDIT.PAS
  47.      and TVDEMO.PAS (both by Borland). So I added a
  48.      description how to generate it, instead of the
  49.      whole file.
  50.    Fix:
  51.      Replacement/addition for the buggy routine
  52.  
  53.    Some improvements are added, in a similar form.
  54.  
  55.  
  56. Bug: procedure TFileEditor.InitBuffer (Unit Editors)
  57.   TFileEditor.NewBuffer allocates 0 bytes, but does not set BufSize
  58.   to 0. Now, if TFileEditor.Load loads a TFileEditor from a stream,
  59.   BufSize is read from the stream, too, and has its old value.
  60.   InitBuffer (called by TEditor.Load) ignores it, so the content
  61.   of the editor is loaded into memory, which was never allocated
  62.   -> the program will crash. So you can't use TFileEditors, if you
  63.   store and load the desktop.
  64. Example:
  65.   Compile the file EDIT.PAS to disk and start it. Open two edit
  66.   windows via File!New, type in some text and save them. Do not
  67.   close the windows! Save the desktop with Windows!Save desktop,
  68.   then reload it with Windows!Retrieve and type a single key:
  69.   The actual edit window will show some weird chars in the
  70.   beginning of the first line. Edit the text in one window and
  71.   then select the other one; watch the effects. If you exit the
  72.   program, sometimes your system hangs because of corrupted
  73.   memory control blocks.
  74. Fix:
  75.   procedure TFileEditor.InitBuffer;
  76.   begin
  77.     NewBuffer(Pointer(Buffer));
  78.   (* Bugfix 13.05.91 JS: consider BufSize! TEditor.InitBuffer
  79.      allocates BufSize bytes, this routine allocates 0 Bytes,
  80.      but does not set BufSize to the correct value. If BufSize
  81.      is <>0 (e.g. after TEditor.Load from a stream), the pro-
  82.      gram will crash. *)
  83.     BufSize:=0;
  84.   end;
  85.  
  86.  
  87. Bug: function IScan (Unit Editors)
  88.   In this assembly-routine the programmer forgot, that MOV does
  89.   not set the flags. If the search string nearly matches the last
  90.   chars in the text, the routine runs over the end of the text --
  91.   eventually replacing text! Here is an example:
  92.     Let '123456' be the text, and search for '45z'.
  93.     The routine scans the text '1234' for the '4' and finds it:
  94.          123456
  95.             45z
  96.     Then it compares the rest, finds the difference and skips
  97.     this occurence. CX (number the chars left in the text) is
  98.     now 0, but the routine just MOVs it back from DX, jumping
  99.     then with JNE. Now it is behind the end of text!
  100. Example:
  101.   TVDEMO\TVEDIT.PAS. Open a new edit window and type "123456"
  102.   without the quote marks. Do not terminate the line with
  103.   Enter! Press the Home key, then Ctrl-Q F to invoke the Find
  104.   dialog. Enter "45z" as search text (without the quote marks)
  105.   and press Enter (Case sensitivity is unselected by default):
  106.   Your system hangs (sometimes wrong occurences are shown, or
  107.   the search wraps around).
  108. Fix:
  109.   (* Comment: The only change needed is the line marked with ***.
  110.      But for better use of TEditor objects outside the USA and
  111.      GB, it's better to use the DOS codepage (MSDOS3.X or higher
  112.      required) for case conversion. *)
  113.  
  114.   { Improvement JS: UpperCase uses DOS codepage }
  115.   procedure DOSUpCase; assembler;
  116.   { a dummy to get a pointer in the codesegment }
  117.   asm
  118.           DD 0
  119.   end;
  120.  
  121.   function UpperCase:Char ; assembler ;
  122.   { changes lower case to upper case letters, using DOS codepage.
  123.     does not need DS to point to Turbo's global data segment.
  124.     input : AL char
  125.     output: AL upper case of it }
  126.   asm
  127.           CMP  AL,'a'           { normal lower case chars.. }
  128.           JB   @@1
  129.           CMP  AL,'z'
  130.           JBE  @@4              { .. get normal treatment. }
  131.           DB   $2E,$FF,$1E      { this is a CALLF [cs:] }
  132.           DW   DOSUpCase        { all others are converted using }
  133.           JMP  @@1              { the DOS codepage }
  134.   @@4:
  135.           SUB AL,20H
  136.   @@1:
  137.   end ;
  138.  
  139.   function UpCase(c:Char): Char; assembler;
  140.   { should be exported, i.e. included in interface }
  141.   asm
  142.           MOV   AL,c
  143.           CALL UpperCase
  144.   end;
  145.  
  146.   function IScan(var Block; Size: Word; Str: String): Word; assembler;
  147.   var
  148.     S: String;
  149.   asm
  150.           PUSH  DS
  151.           MOV   AX,SS           { copy the Str to S, converting it.. }
  152.           MOV   ES,AX           { to upper case }
  153.           LEA   DI,S
  154.           LDS   SI,Str
  155.           XOR   AH,AH
  156.           LODSB                 { copy string length }
  157.           STOSB
  158.           MOV   CX,AX
  159.           MOV   BX,AX
  160.           JCXZ  @@9
  161.   @@1:    LODSB                 { load each char from Str.. }
  162.           CALL  UpperCase       { get upper case of it.. }
  163.           STOSB                 { and store it to S }
  164.           LOOP  @@1
  165.           SUB   DI,BX           { goto beginning of S (without length byte) }
  166.           LDS   SI,Block
  167.           MOV   CX,Size
  168.           JCXZ  @@8
  169.           CLD
  170.           SUB   CX,BX           { no need to examine the last chars in..}
  171.           JB    @@8             { Block, the search string won't fit }
  172.           INC   CX
  173.   @@4:    MOV   AH,ES:[DI]      { search for the first char of search string }
  174.   @@5:    LODSB
  175.           CALL  UpperCase
  176.           CMP AL,AH             { compare chars from Block with first char.. }
  177.           LOOPNE @@5            { of search string until found }
  178.           JNE   @@8             { no occurence -> goto end }
  179.           DEC   SI              { compare the whole search string }
  180.           MOV   DX,CX           { save number of remaining bytes in Block }
  181.           MOV   CX,BX           { get search string length }
  182.   @@6:    REPE  CMPSB           { exact match.. }
  183.           JE    @@10            { up to end of search string -> success }
  184.           MOV   AL,DS:[SI-1]    { else: }
  185.           CALL  UpperCase       { compare upper case }
  186.           CMP   AL,ES:[DI-1]
  187.           JE    @@6             { matches -> continue }
  188.           SUB   CX,BX           { else compare failed; restore pointers.. }
  189.           ADD   SI,CX           { in Block.. }
  190.           ADD   DI,CX           { and search string }
  191.           INC   SI
  192.           MOV   CX,DX           { restore number of remaining bytes in Block }
  193.           OR    CX,CX           { *** MOV does not modify the flags! }
  194.           JNE   @@4             { zero remaining bytes -> end }
  195.   @@8:    XOR   AX,AX           { end without success: return 0 }
  196.           JMP   @@11
  197.   @@9:    MOV   AX, 1           { end with empty search string:.. }
  198.           JMP   @@11            { pointer to next char }
  199.   @@10:   SUB   SI,BX           { end with success: return pointer to.. }
  200.           MOV   AX,SI           { found occurence }
  201.           SUB   AX,WORD PTR Block
  202.           INC   AX
  203.   @@11:   DEC   AX              { set correct range of AX for BOOLEAN }
  204.           POP DS
  205.   end;
  206.  
  207.   { an init routine, replacing the END. at the end of EDITORS.PAS: }
  208.   const RetFar:Byte=$CB ;
  209.   var i: Integer;
  210.   begin
  211.     { Improvement JS: UpperCase uses DOS codePage }
  212.     asm
  213.               push  ds
  214.               mov   ds,PrefixSeg
  215.               mov   dx,$D0        { DS:DX = 32 bytes scratch area in the PSP }
  216.               mov   ax,$3800      { get extended country information }
  217.               int   21h
  218.               mov   bx,dx
  219.               mov   ax,[bx+$12]   { Pointer to case conversion routine.. }
  220.               mov   bx,[bx+$14]   { for chars >80h }
  221.               pop   ds
  222.               jnc   @@ok          { if DOS reports error, set it to RETF }
  223.               mov   ax,Offset RetFar
  224.               mov   bx,ds
  225.     @@ok:
  226.               mov   word ptr cs:DOSUpCase,ax
  227.               mov   word ptr cs:DOSUpCase+2,bx
  228.     end ;
  229.   end.
  230.  
  231.  
  232. Bug: procedure TEditor.HandleEvent (Unit Editors)
  233.   This routine consumes all cmScrollBarChanged-events, without
  234.   testing the sender. With TEditor, everything is ok, but with
  235.   TMemo, there is a problem: this object cannot coexist in a
  236.   TDialog with other objects having scrollbars. The test, whe-
  237.   ther a cmScrollBarChanged-event is from one of its own scroll
  238.   bars is done in the local procedure CheckScrollBar, but the
  239.   HandleEvent routine clears the event in any case.
  240. Example:
  241.   TESTMEMO. Start it and press F1 to get a MemoDialog, where a
  242.   TMemo field is together with a TListviewer, both having scroll-
  243.   bars. Try to position the focus in the TListbox with the scroll-
  244.   bar or with the cursor keys (they are translated by the scroll-
  245.   bar as well): it won't work. On the contrary, the TMemo works
  246.   fine.
  247. Fix:
  248.   TEditor.HandleEvent(var Event: TEvent);
  249.  
  250.   (* ... several lines skipped ... *)
  251.  
  252.   { Bugfix JS: function CheckScrollBar:Boolean returns False, if
  253.     the sending scrollbar was not the scrollbar in question. }
  254.   function CheckScrollBar(P: PScrollBar; var D: Integer): Boolean;
  255.   begin
  256.     if (Event.InfoPtr = P) and (P^.Value <> D) then
  257.     begin
  258.       D := P^.Value;
  259.       Update(ufView);
  260.       CheckScrollBar := True;
  261.     end
  262.     else CheckScrollBar := False;
  263.   end;
  264.  
  265.   begin
  266.     TView.HandleEvent(Event);
  267.     ConvertEvent(Event);
  268.  
  269.   (* ... several lines skipped ... *)
  270.  
  271.       evBroadcast:
  272.         case Event.Command of
  273.           cmScrollBarChanged:
  274.             { Bugfix JS: function CheckScrollBar():Boolean returns False,
  275.               if the sending scrollbar was not the scrollbar in question.
  276.               The EXIT prevents the Event from being cleared. }
  277.             if not(CheckScrollBar(HScrollBar, Delta.X) or
  278.                    CheckScrollBar(VScrollBar, Delta.Y)) then Exit;
  279.           else Exit;
  280.         end;
  281.     end;
  282.     ClearEvent(Event);
  283.   end;
  284.  
  285.  
  286. Bug: function TEditor.InsertBuffer (Unit Editors)
  287.   Overwriting chars in an TEditor object is done in TEditor.Handle-
  288.   Event by marking the next char as block and calling InsertBuffer
  289.   via InsertText. This routine checks, whether there is enough
  290.   memory and complains (edOutOfMemory), but does not reset the
  291.   block marker. If you now press backspace, the block is deleted
  292.   (i.e. the char under the cursor), not the char on the left side
  293.   of the cursor.
  294. Example:
  295.   Be sure to compile TVDEMOS\TVEDIT.PAS without the Range Check
  296.   option; there seems to be another minor bug concerning Integer
  297.   and Word types. Start TVEDIT.EXE, open a new edit window and
  298.   start typing until the messagebox 'Not enough memory for this
  299.   operation' comes up. Press Enter to close the messagebox, move
  300.   the cursor in the middle of a line and type until the messagebox
  301.   comes up again. Press Enter to close it again and then press
  302.   Backspace. Not the char on the left side of the cursor will be
  303.   deleted, but the char at cursor position.
  304. Fix:
  305.   function TEditor.InsertBuffer(var P: PEditBuffer; Offset, Length: Word;
  306.     AllowUndo, SelectText: Boolean): Boolean;
  307.   var
  308.     SelLen, DelLen, SelLines, Lines: Word;
  309.     NewSize: Longint;
  310.   begin
  311.     InsertBuffer := True;
  312.     Selecting := False;
  313.     SelLen := SelEnd - SelStart;
  314.     if (SelLen = 0) and (Length = 0) then Exit;
  315.     DelLen := 0;
  316.     if AllowUndo then
  317.       if CurPtr = SelStart then DelLen := SelLen else
  318.         if SelLen > InsCount then DelLen := SelLen - InsCount;
  319.     NewSize := Longint(BufLen + DelCount - SelLen + DelLen) + Length;
  320.     if NewSize > BufLen + DelCount then
  321.       if (NewSize > $FFF0) or not SetBufSize(NewSize) then
  322.       begin
  323.         EditorDialog(edOutOfMemory, nil);
  324.         { Bugfix JS: reset block markers to avoid abnormal behaviour
  325.           of a following BackSpace: }
  326.         SelEnd := SelStart;
  327.         InsertBuffer := False;
  328.         Exit;
  329.       end;
  330.  
  331.   (* ... several lines skipped ... *)
  332.  
  333.     SetBufSize(BufLen + DelCount);
  334.     if (SelLines = 0) and (Lines = 0) then Update(ufLine) else Update(ufView);
  335.   end;
  336.  
  337. Bug: function NoWildChars (Unit StdDlg)
  338.   This routine is used by TFileDialog-objects to delete wildcards
  339.   in filenames. If called with an empty argument, it overwrites
  340.   the stack. Try it: just give first '*' as mask, then a name with
  341.   no extension in a TFileDialog.
  342. Example:
  343.   TVDEMOS\TVDEMO.PAS. Create the file TEST (no extension!), then
  344.   start TVDEMO.EXE. Press F3 to invoke the FileOpen dialog. Type
  345.   "*" without the quote marks, press Enter, choose TEST from the
  346.   file list and press Enter again: The system hangs.
  347. Fix:
  348.   function NoWildChars(S: String): String; assembler;
  349.   asm
  350.           PUSH  DS
  351.           LDS   SI,S            { pointer to argument string }
  352.           LES   DI,@Result      { same to result string }
  353.           XOR   AX,AX
  354.           LODSB                 { get length of argument string }
  355.           { Bugfix JS: test for empty argument string }
  356.           OR    AL,AL           { length=0 ? }
  357.           JE    @@3             { -> result = '' }
  358.           XCHG  AX,CX           { else: }
  359.           INC   DI              { skip result length byte }
  360.   @@1:    LODSB                 { get char from argument string }
  361.           CMP   AL,'?'          { '?' or '*' ? }
  362.           JE    @@2             { then skip it.. }
  363.           CMP   AL,'*'
  364.           JE    @@2
  365.           STOSB                 { else copy it into result string }
  366.   @@2:    LOOP  @@1
  367.           XCHG  AX,DI           { calculate length of result string.. }
  368.           MOV DI,WORD PTR @Result
  369.           SUB AX,DI             { as Endoffset+1 - Startoffset }
  370.           DEC     AX            { don't count the length byte }
  371.   @@3:
  372.           STOSB                 { set length of result string }
  373.           POP DS
  374.   end;
  375.  
  376. Bug: procedure THelpTopic.AddCrossRef (Unit HelpFile)
  377.   In this routine the programmer allocates memory and then
  378.   forgets to use the pointer to it. He just forgot a line.
  379. Example:
  380.   No example. 'The code is obvious.'
  381. Fix:
  382.   procedure THelpTopic.AddCrossRef(Ref: TCrossRef);
  383.   var
  384.     P: PCrossRefs;
  385.   begin
  386.     GetMem(P, (NumRefs+1) * SizeOf(TCrossRef));
  387.     if NumRefs > 0 then
  388.     begin
  389.       Move(CrossRefs^, P^, NumRefs * SizeOf(TCrossRef));
  390.       FreeMem(CrossRefs, NumRefs * SizeOf(TCrossRef));
  391.     end;
  392.     { Bugfix JS: the following line is missing in the original }
  393.     CrossRefs := P;
  394.     CrossRefs^[NumRefs] := Ref;
  395.     Inc(NumRefs);
  396.   end;
  397.  
  398. Bug: function THelpIndex.Position (Unit HelpFile)
  399.   If called with a negative argument, it returns random values,
  400.   since it checks only for the upper bound, not for the lower
  401.   one. The help compiler TVHC uses -1 for unknown topics, so
  402.   this doesn't work.
  403. Example:
  404.   Compile TVDEMOS\TVDEMO.PAS to disk. Then add the
  405.   line
  406.     {abc}
  407.   to the first topic in TVDEMOS\DEMOHELP.TXT and
  408.   compile it with
  409.      TVHC DEMOHELP.TXT
  410.   This will produce DEMOHELP.HLP and DEMOHELP.PAS.
  411.   Start TVDEMO.EXE, press F1 to see the general help
  412.   and then Enter to follow the cross reference 'abc'.
  413.   You will not see the text 'No help available in this
  414.   context.', as intended by HELPFILE.PAS, but get a
  415.   runtime error (if you compiled TVDEMO with Range Check
  416.   option) or a randomly chosen help text if any (without
  417.   Range checking).
  418. Fix:
  419.   function THelpIndex.Position(I: Integer): Longint;
  420.   begin
  421.     if (-1 < I) and (I < Size) then Position := Index^[I]
  422.     else Position := -1;
  423.   end;
  424.  
  425. Bug: procedure AddToBuffer (Programm TVHC)
  426.   No range checking is done in this routine. If a paragraph is
  427.   longer than specified in the constant BufferSize (default:1024),
  428.   memory behind the buffer is overwritten, resulting in crash.
  429. Example:
  430.   Create a file TESTHELP.TXT with this content:
  431.     .topic TestContext
  432.     The following paragraph is too long to fit into the
  433.     standard-sized buffer of TVHC.PAS:
  434.       1234567890123456789012345678901234567890
  435.       1234567890123456789012345678901234567890
  436.  
  437.         .. another 100 lines likes these ..
  438.  
  439.       1234567890123456789012345678901234567890
  440.       1234567890123456789012345678901234567890
  441.   Now start TVHC on it:
  442.     TVHC TESTHELP.TXT
  443.   Your system will hang, if you haven't compiled TVHC with Range
  444.   Check option, otherwise you will get a runtime error 204.
  445. Fix:
  446.   procedure AddToBuffer(var Line: String; Wrapping: Boolean); assembler;
  447.   asm
  448.           PUSH    DS
  449.           CLD
  450.           PUSH    DS
  451.           POP     ES
  452.           MOV     DI,OFFSET Buffer
  453.           ADD     DI,Ofs
  454.           LDS     SI,Line
  455.           LODSB
  456.           XOR     AH,AH
  457.           { Bugfix JS: the following test is missing in the original
  458.             version. Causes crashes on buffer overflow }
  459.           MOV     BX,BufferSize { BufferSize-Ofs is the space left in Buffer }
  460.           SUB     BX,ES:Ofs
  461.           CMP     BX,AX         { AX holds the needed amount of space }
  462.           JAE     @@0           { enough -> ok }
  463.           MOV     AX,BX         { else just fill the Buffer up }
  464.   @@0:
  465.           ADD     ES:Ofs,AX
  466.           XCHG    AX,CX
  467.           JCXZ    @@3           { don't copy 64K if there is nothing to do }
  468.           REP     MOVSB
  469.           CMP     ES:Ofs,BufferSize
  470.           JE      @@3           { don't append ' '/#13 if there is no room }
  471.           XOR     AL,AL
  472.           INC     ES:Ofs
  473.           TEST    Wrapping,1    { Only add a #13, line terminator, if not }
  474.           JE      @@1           { currently wrapping the text. Otherwise  }
  475.           MOV     AL,' '-13     { add a ' '.                              }
  476.   @@1:    ADD     AL,13
  477.   @@2:    STOSB
  478.   @@3:
  479.           POP     DS
  480.   end;
  481.  
  482. Bug: procedure THistory.Draw (Unit Dialogs)
  483.   For the history button sides, the chars ASCII 221 and 222 are
  484.   used. These chars are _not_ included in codepages other than
  485.   437 (e.g. codepage 850, recommended by IBM for europe). So,
  486.   the button looks somewhat awful in europe.
  487. Example:
  488.   To use codepage 850 with your display, include the lines
  489.   (with correct paths, of course)
  490.       nlsfunc.exe country.sys
  491.       mode con cp prepare=((850)ega.cpi)
  492.   in your AUTOEXEC.BAT and type CHCP 850 at the DOS prompt after
  493.   startup. DOS will complain, because you haven't prepared this
  494.   codepage for all devices, but this doesn't matter. Start
  495.   TVDEMOS\TVDEMO and press F3 to invoke a TFileDialog with a
  496.   history button on the left side of the 'Name' input line.
  497.   Look at the System-menu symbol for another example of such
  498.   incompatibly written software.
  499. Fix:
  500.   No fix.
  501.  
  502. Bug: integrated assembler
  503.   The integrated assembler doesn't generate the correct code for
  504.   lines like this:
  505.  
  506.          MOV AX,[WORD PTR BX]
  507.  
  508.   The alternative form
  509.  
  510.          MOV AX,WORD PTR [BX]
  511.  
  512.   is handled properly. This is especially bad, since the first form
  513.   is TASM syntax in Ideal mode, while the latter is MASM syntax.
  514. Example:
  515.   Compile TESTASM.PAS to disk. Then start DEBUG with TESTASM.EXE
  516.   and type 'u' to unassemble the code. You will see
  517.     MOV  BX,0038
  518.     MOV  AX,[0000]
  519.     MOV  AX,[BX]
  520. Fix:
  521.   No fix.
  522.  
  523.  
  524. Some improvements:
  525. Behaviour: ^T in TVEdit sometimes deletes more than the next word.
  526. Explanation:
  527.   ^T deletes _up to the next_ word, to be exact: up to the next
  528.   char out of
  529.     WordChars: set of Char = ['0'..'9', 'A'..'Z', '_', 'a'..'z']
  530.   This will usually be just the next word, but can be more. The
  531.   IDE editor first skips the current word if the cursor is in one.
  532.   Then it skips blanks and tabs up to the next non-blank/non-tab.
  533. Example:
  534.   EDIT.PAS. Open a new edit window and type this line:
  535.     abc[[[[123]
  536.   Press Home to position the cursor on the 'a'. Press ^T; this
  537.   will delete 'abc[[[['. The TurboPascal Editor would delete 'abc'.
  538. Fix:
  539.   function TEditor.NextWord(P: Word): Word;
  540.   begin
  541.     if BufChar(P) in WordChars then
  542.       while (P < BufLen) and (BufChar(P) in WordChars) do
  543.         P := NextChar(P)
  544.     else
  545.       P := NextChar(P);
  546.     while (P < BufLen) and ((BufChar(P) = ' ') or (BufChar(P) = #9)) do
  547.       P := NextChar(P);
  548.     NextWord := P;
  549.   end ;
  550.  
  551. Behaviour: ^QF followed by ^L followed by Space deletes words in TVEdit.
  552. Explanation:
  553.   If you mark a block manually and type a key, the block will be
  554.   replaced by the key. Because occurences of the search string
  555.   are marked as block, the described effect is seen. If you
  556.   really want to avoid it, you have to change TEditor.HandleEvent
  557.   to clear the blockmarkers before inserting a normal char.
  558. Example:
  559.   EDIT.PAS. Open a new edit window and type this:
  560.     1234567890
  561.   Move the cursor to the '3', hold down a Shift key and move the
  562.   cursor to the '8' to mark the string '34567'. Press the space
  563.   bar; this will replace '34567' by ' '.
  564. Fix:
  565.   TEditor.HandleEvent(var Event: TEvent);
  566.  
  567.   (* ... several lines skipped ... *)
  568.  
  569.   begin
  570.  
  571.   (* ... several lines skipped ... *)
  572.  
  573.       evKeyDown:
  574.         case Event.CharCode of
  575.           #9,#32..#255:
  576.             begin
  577.               Lock;
  578.               { Improvement JS: reset blockmarkers if not overwriting }
  579.               if Overwrite then
  580.                 begin
  581.                   if CurPtr <> LineEnd(CurPtr) then SelEnd := NextChar(CurPtr)
  582.                 end
  583.               else
  584.                 SelEnd := SelStart;
  585.               InsertText(@Event.CharCode, 1, False);
  586.               TrackCursor(CenterCursor);
  587.               Unlock;
  588.             end;
  589.         else
  590.           Exit;
  591.         end;
  592.  
  593.   (* ... several lines skipped ... *)
  594.  
  595.   end;
  596.  
  597.  
  598. What I thought to be a bug, but was not:
  599. Bug: local assembly-procedures in assembly-procedures
  600.   Here the compiler seems to have problems with the parameter
  601.   sizes. Look at this:
  602.  
  603.     function FnTruncSet(Pattern:String):Boolean ; assembler ;
  604.         procedure Number ; assembler ;
  605.         asm
  606.           [....]
  607.         end ;
  608.     asm
  609.       [....]
  610.       call Number
  611.       [....]
  612.     end ;
  613.  
  614.   For the procedure Number, the compiler generates a RET 2 instead
  615.   of RET. I have no idea, why it wants to pop 2 bytes while having
  616.   no argument; in this form, it will crash.
  617. Explanation:
  618.   In the Programmer's reference, nested procedures are described.
  619.   TurboPascal always pushes BP onto the stack to allow local pro-
  620.   cedures to access the arguments of the enclosing routine. So, it
  621.   has to pop 2 Bytes at the end.
  622. Fix:
  623.   RTFM. Or, TurboPascal should not do this, because the same manual
  624.   states that ASSEMBLER routines do not get a stack frame, if they
  625.   have no arguments and local variables. So BP doesn't have to be
  626.   pushed, it already has its correct value inside the local routine.
  627.  
  628. ---------------------------  EDIT.PAS  ------------------------------
  629. { This text describes changes to be applied to the program TVEDIT.PAS
  630.   from Borland. The changes will extend it to allow storing and reloa-
  631.   ding the desktop with routines from TVDEMO.PAS. All changes are
  632.   described in the form
  633.     (* TVEDIT.PAS original <place/routine name> *)
  634.       ... program text from TVEDIT.PAS ...
  635.     (* EDIT.PAS replacement *)
  636.       ... some other program text ...
  637.   Just replace (or better: add) as described, and you will get EDIT.PAS
  638. }
  639.  
  640. (* TVEDIT.PAS original, at the top: *)
  641.   const
  642.     cmOpen       = 100;
  643.     cmNew        = 101;
  644.     cmChangeDir  = 102;
  645.     cmDosShell   = 103;
  646.     cmCalculator = 104;
  647.     cmShowClip   = 105;
  648.  
  649. (* EDIT.PAS replacement *)
  650.   const
  651.     cmOpen       = 100;
  652.     cmNew        = 101;
  653.     cmChangeDir  = 102;
  654.     cmDosShell   = 103;
  655.     cmCalculator = 104;
  656.     cmShowClip   = 105;
  657.     cmSaveDesktop     =1000;
  658.     cmRetrieveDesktop =1001;
  659.  
  660.  
  661. (* TVEDIT.PAS original, at the top *)
  662.   type
  663.     PEditorApp = ^TEditorApp;
  664.     TEditorApp = object(TApplication)
  665.       constructor Init;
  666.       destructor Done; virtual;
  667.       procedure HandleEvent(var Event: TEvent); virtual;
  668.       procedure InitMenuBar; virtual;
  669.       procedure InitStatusLine; virtual;
  670.       procedure OutOfMemory; virtual;
  671.     end;
  672.  
  673. (* EDIT.PAS replacement *)
  674.   type
  675.     PEditorApp = ^TEditorApp;
  676.     TEditorApp = object(TApplication)
  677.       constructor Init;
  678.       destructor Done; virtual;
  679.       procedure HandleEvent(var Event: TEvent); virtual;
  680.       procedure InitMenuBar; virtual;
  681.       procedure InitStatusLine; virtual;
  682.       procedure LoadDesktop(var S: TStream);
  683.       procedure StoreDesktop(var S: TStream);
  684.       procedure OutOfMemory; virtual;
  685.     end;
  686.  
  687. (* TVEDIT.PAS original, TEditorApp.Init *)
  688.     if H > HeapSize then BufHeapSize := H - HeapSize else BufHeapSize := 0;
  689.     InitBuffers;
  690.     TApplication.Init;
  691.     DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  692.       cmUndo, cmFind, cmReplace, cmSearchAgain]);
  693.  
  694. (* EDIT.PAS replacement
  695.     if H > HeapSize then BufHeapSize := H - HeapSize else BufHeapSize := 0;
  696.     InitBuffers;
  697.     RegisterObjects;
  698.     RegisterViews;
  699.     RegisterMenus;
  700.     RegisterDialogs;
  701.     RegisterApp;
  702.     RegisterEditors;
  703.     RegisterCalc;
  704.     TApplication.Init;
  705.     DisableCommands([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  706.       cmUndo, cmFind, cmReplace, cmSearchAgain]);
  707.  
  708.  
  709. (* TVEDIT.PAS, original does not include the following routines: *)
  710. (* EDIT.PAS addition *)
  711.   { copied from TVDEMO.PAS and modified TTVDemo to TEditorApp }
  712.   { Since the safety pool is only large enough to guarantee that allocating
  713.     a window will not run out of memory, loading the entire desktop without
  714.     checking LowMemory could cause a heap error.  This means that each
  715.     window should be read individually, instead of using Desktop's Load.
  716.   }
  717.  
  718.   procedure TEditorApp.LoadDesktop(var S: TStream);
  719.   var
  720.     P: PView;
  721.  
  722.   procedure CloseView(P: PView); far;
  723.   begin
  724.     Message(P, evCommand, cmClose, nil);
  725.   end;
  726.  
  727.   begin
  728.     if Desktop^.Valid(cmClose) then
  729.     begin
  730.       Desktop^.ForEach(@CloseView); { Clear the desktop }
  731.       repeat
  732.         P := PView(S.Get);
  733.         Desktop^.InsertBefore(ValidView(P), Desktop^.Last);
  734.       until P = nil;
  735.     end;
  736.   end;
  737.  
  738.   procedure TEditorApp.StoreDesktop(var S: TStream);
  739.  
  740.   procedure WriteView(P: PView); far;
  741.   begin
  742.     if P <> Desktop^.Last then S.Put(P);
  743.   end;
  744.  
  745.   begin
  746.     Desktop^.ForEach(@WriteView);
  747.     S.Put(nil);
  748.   end;
  749.  
  750.  
  751. (* TVEDIT.PAS original, TEditorApp.HandleEvent does not include the
  752.    following local routines: *)
  753. (* EDIT.PAS addition *)
  754.   { copied from TVDEMO.PAS and modified filenames }
  755.   procedure RetrieveDesktop;
  756.   var
  757.     S: PStream;
  758.   begin
  759.     S := New(PBufStream, Init('TVEDIT.DSK', stOpenRead, 1024));
  760.     if LowMemory then OutOfMemory
  761.     else if S^.Status <> stOk then
  762.       MessageBox('Could not open desktop file', nil, mfOkButton + mfError)
  763.     else
  764.     begin
  765.       LoadDesktop(S^);
  766.       if S^.Status <> stOk then
  767.         MessageBox('Error reading desktop file', nil, mfOkButton + mfError);
  768.     end;
  769.     Dispose(S, Done);
  770.   end;
  771.  
  772.   procedure SaveDesktop;
  773.   var
  774.     S: PStream;
  775.     F: File;
  776.   begin
  777.     S := New(PBufStream, Init('TVEDIT.DSK', stCreate, 1024));
  778.     if not LowMemory and (S^.Status = stOk) then
  779.     begin
  780.       StoreDesktop(S^);
  781.       if S^.Status <> stOk then
  782.       begin
  783.         MessageBox('Could not create TVEDIT.DSK.', nil, mfOkButton + mfError);
  784.         {$I-}
  785.         Dispose(S, Done);
  786.         Assign(F, 'TVEDIT.DSK');
  787.         Erase(F);
  788.         Exit;
  789.       end;
  790.     end;
  791.     Dispose(S, Done);
  792.   end;
  793.  
  794.  
  795. (* TVEDIT.PAS original, TEditorApp.HandleEvent *)
  796.           cmCalculator: Calculator;
  797.           cmShowClip: ShowClip;
  798.           cmTile: Tile;
  799.           cmCascade: Cascade;
  800.         else
  801.           Exit;
  802.  
  803. (* EDIT.PAS replacement *)
  804.           cmCalculator: Calculator;
  805.           cmShowClip: ShowClip;
  806.           cmTile: Tile;
  807.           cmCascade: Cascade;
  808.           cmSaveDesktop: SaveDesktop;
  809.           cmRetrieveDesktop: RetrieveDesktop;
  810.         else
  811.           Exit;
  812.  
  813.  
  814. (* TVEDIT.PAS original, TEditorApp.InitMenuBar *)
  815.       NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, hcNoContext,
  816.       NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  817.       NewLine(
  818.       NewItem('Ca~l~culator', '', kbNoKey, cmCalculator, hcNoContext,
  819.       nil)))))))))),
  820.     nil)))))));
  821. end;
  822.  
  823. (* EDIT.PAS replacement *)
  824.         NewItem('~P~revious', 'Shift-F6', kbShiftF6, cmPrev, hcNoContext,
  825.         NewItem('~C~lose', 'Alt-F3', kbAltF3, cmClose, hcNoContext,
  826.         NewLine(
  827.         NewItem('Ca~l~culator', '', kbNoKey, cmCalculator, hcNoContext,
  828.         NewLine(
  829.         NewItem('~R~etrieve desktop', '', kbNoKey, cmRetrieveDesktop, hcNoContex
  830.         NewItem('Sa~v~e desktop', '', kbNoKey, cmSaveDesktop, hcNoContext,
  831.         nil)))))))))))))
  832.       nil)))))));
  833.   end;
  834.  
  835. ---------------------------  TESTASM.PAS  ---------------------------
  836. program TestAsm;
  837. begin
  838.   asm
  839.     MOV  BX,OFFSET PrefixSeg
  840.     MOV  AX,[WORD PTR BX]
  841.     MOV  AX,WORD PTR [BX]
  842.   end;
  843. end.
  844. ---------------------------  TESTMEMO.PAS  --------------------------
  845. program TestMemos ;
  846. uses Objects,Drivers,Views,Menus,Dialogs,Editors,App;
  847.  
  848. const
  849.   cmMemo = 1000;
  850.  
  851. type
  852.   PDemoListViewer = ^TDemoListViewer;
  853.   TDemoListViewer = object(TListViewer)
  854.     function GetText(Item: Integer; MaxLen: Integer): String; virtual;
  855.   end;
  856.  
  857. type
  858.   TMemoApp=object(TApplication)
  859.     procedure InitStatusLine; virtual;
  860.     procedure HandleEvent(var Event:TEvent); virtual;
  861.   end;
  862.  
  863. function TDemoListViewer.GetText(Item: Integer; MaxLen: Integer): String;
  864. var
  865.   S: String[5];
  866. begin
  867.   Str(Item, S);
  868.   GetText := copy('Item '+S,1,MaxLen);
  869. end;
  870.  
  871. procedure TMemoApp.InitStatusLine;
  872. var
  873.   R: TRect;
  874. begin
  875.   GetExtent(R);
  876.   R.A.Y := R.B.Y - 1;
  877.   New(StatusLine, Init(R,
  878.     NewStatusDef(0, $FFFF,
  879.       NewStatusKey('~Alt-X~ Exit', kbALtX, cmQuit,
  880.       NewStatusKey('~F1~ MemoDialog', kbF1, cmMemo,
  881.       nil)),
  882.     nil)));
  883. end;
  884.  
  885. procedure TMemoApp.HandleEvent(var Event:TEvent);
  886. var
  887.   R: TRect;
  888.   D: PDialog;
  889.   V,W: PView;
  890. begin
  891.   TApplication.HandleEvent(Event);
  892.   if (Event.What = evCommand) and (Event.Command = cmMemo) then
  893.     begin
  894.       R.Assign(22, 3, 58, 19);
  895.       D := New(PDialog,Init(R, 'MemoDialog'));
  896.       with D^ do
  897.         begin
  898.           R.Assign(12, 2, 13, 14);
  899.           V := New(PScrollBar, Init(R));
  900.           Insert(V);
  901.           R.Assign(2, 2, 12, 14);
  902.           V := New(PDemoListViewer, Init(R, 1, nil, PScrollBar(V)));
  903.           PDemoListViewer(V)^.SetRange(20);
  904.           Insert(V);
  905.  
  906.           R.Assign(33, 2, 34, 13);
  907.           V := New(PScrollBar, Init(R));
  908.           Insert(V);
  909.           R.Assign(14, 13, 33, 14);
  910.           W := New(PScrollBar, Init(R));
  911.           Insert(W);
  912.           R.Assign(14, 2, 33, 13);
  913.           V := New(PMemo, Init(R, PScrollBar(W), PScrollBar(V), nil, 1024));
  914.           Insert(V);
  915.         end;
  916.       DeskTop^.ExecView(D);
  917.       D^.Done;
  918.     end;
  919. end;
  920.  
  921. var MemoApp:TMemoApp;
  922. begin
  923.   MemoApp.Init;
  924.   MemoApp.Run;
  925.   MemoApp.Done;
  926. end.
  927. --------------------  End of bugs!  ---------------------------------
  928. I got an update to TP6.01, but they haven't change anything.
  929. -  J"urgen Schlegelmilch
  930.  
  931.